package com.xdap.common.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.CoreConnectionPNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

/**
 * @AUTH lishushu
 * @TIME 2023/2/21 0021 8:52
 * @DESC (rest请求工具类)
 */
@Service
public class RestClient {

    private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 1000;

    private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 200;

    private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (10 * 60 * 1000);

    @Autowired
    private RestTemplate restTemplate;
    private Logger logger = LoggerFactory.getLogger(this.getClass());


    //@Bean( value ="techkingCommonPluginClient")
    public HttpClient httpClient() {
        PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
        connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
        connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);

        HttpClient defaultHttpClient = new DefaultHttpClient(connectionManager);
        defaultHttpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
                DEFAULT_READ_TIMEOUT_MILLISECONDS);

        return defaultHttpClient;
    }

    public <T> T get(String url, Map<String, Object> param, Class<T> clazz, HttpHeaders headers) {
        return request(url, param, clazz, RequestMethod.GET, headers);
    }

    public <T> T getWithCookie(String url, Map<String, Object> param, Class<T> clazz, String cookie) {
        return request(url, param, clazz, RequestMethod.GET, getHeader(cookie));
    }

    public <T> T post(String url, Map<String, Object> param, Class<T> clazz, HttpHeaders headers) {
        return request(url, param, clazz, RequestMethod.POST, headers);
    }

    public <T> Object post(String url, String jsonStr, Object response, HttpHeaders httpHeaders) {
        Long restStart = System.currentTimeMillis();
        httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        logger.info("=====");
        logger.info("访问地址:" + url);
        logger.info("请求参数:" + jsonStr);
        try {
            HttpEntity<String> entity = new HttpEntity<>(jsonStr, httpHeaders);
            FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
            converter.setFastJsonConfig(new FastJsonConfig());
            List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
            converters.add(converter);
            restTemplate.setMessageConverters(converters);
            ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url, entity, JSONObject.class);
            logger.info("请求结果:{}", responseEntity.getBody());
            response = GsonUtil.toObj(responseEntity.getBody(), response.getClass());
            logger.info("RestClient请求耗时:" + (System.currentTimeMillis() - restStart) + "ms");
            logger.info("=====");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return response;
    }


    public <T> Object post(String url, Object response) {
        Long restStart = System.currentTimeMillis();
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

        HttpEntity<String> formEntity = new HttpEntity<String>(null, httpHeaders);
        logger.info("=====");
        logger.info("访问地址:" + url);
        ResponseEntity<JSONObject> responseEntity = restTemplate.postForEntity(url, formEntity, JSONObject.class);
        logger.info("请求结果:{}", responseEntity.getBody());
        response = GsonUtil.toObj(responseEntity.getBody(), response.getClass());
        logger.info("RestClient请求耗时:" + (System.currentTimeMillis() - restStart) + "ms");
        logger.info("=====");
        return response;
    }

    public <T> T postWithCookie(String url, Map<String, Object> param, Class<T> clazz, String cookie) {
        return request(url, param, clazz, RequestMethod.POST, getHeader(cookie));
    }

    public <T> T request(String url, Map<String, Object> param, Class<T> clazz,
                         RequestMethod method, HttpHeaders headers) {
        logger.info("method = " + method);
        ResponseEntity<String> response = this.execute(url, method, param, headers);

        T output = null;
        if (response != null) {
            logger.info("statusCode = " + response.getStatusCode());
            String body = response.getBody();
            logger.info("body = " + body);
            if (clazz == String.class) {
                output = (T) body;
            } else {
                output = GsonUtil.toObj(body, clazz);
            }
        }
        logger.info("=====");
        return output;
    }

    public ResponseEntity<String> execute(String url, RequestMethod method,
                                          Map<String, Object> param, HttpHeaders headers) {
        logger.info("url = " + url);
        String json = "";
        if (RequestMethod.POST == method && param != null) {
            json = GsonUtil.toJson(param);
            logger.info("post-json = " + json);
        }
        HttpEntity<String> formEntity = new HttpEntity<>(json, headers);
        ResponseEntity<String> response = null;
        if (RequestMethod.POST == method) {
            response = restTemplate.postForEntity(url, formEntity, String.class);
        } else if (RequestMethod.GET == method) {
            if (param != null) {
                StringBuilder sb = new StringBuilder().append('?');
                param.keySet().forEach(e -> sb.append(e).append('=').append(encode(param.get(e))).append('&'));
                if (sb.length() > 0) {
                    sb.deleteCharAt(sb.length() - 1);
                }
                url += sb.toString();
                logger.info("get-url = " + url);
            }
            // response = restTemplate.getForEntity(url, String.class, headers); // server端获取不到cookie
            response = restTemplate.exchange(url, HttpMethod.GET, formEntity, String.class);
        } else {
            logger.error("暂不支持的 http method，url={}, method={}, param={}", url, method, param);
        }
        return response;
    }

    public <T> ResponseEntity<T> execute(String url, MultiValueMap<String, Object> body,
                                         HttpHeaders headers, Class<T> clazz) {
        logger.info("url = " + url);

        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

        ResponseEntity<T> response = restTemplate.postForEntity(url, requestEntity, clazz);

        return response;
    }

    private String encode(Object obj) {
        if (null == obj) {
            return null;
        }
        String str = obj.toString();
        try {
            return URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    private HttpHeaders getHeader(String cookie) {
        HttpHeaders headers = createHeader();
        headers.add("Cookie", cookie);
        return headers;
    }

    public HttpHeaders createHeader(String weiyunToken) {
        HttpHeaders headers = createHeader();
        headers.add("WEIYUN-TOKEN", weiyunToken);
        return headers;
    }

    public HttpHeaders createHeader() {
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        return headers;
    }

    public HttpHeaders createHeader(MediaType mediaType, String accept) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(mediaType);
        headers.add("Accept", accept);
        return headers;
    }

    public String getFullURL(String url, Map<String, Object> requestParams) {
        url = url.replaceAll("([^:])/[/]+", "$1/");
        if (requestParams != null && !requestParams.isEmpty()) {
            UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
            for (String k : requestParams.keySet()) {
                uriBuilder.queryParam(k, requestParams.get(k));
            }
            url = uriBuilder.build().encode().toString();
        }
        return url;
    }
}

